home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 August: Tool Chest / Dev.CD Aug 94.toast / Sample Code / AppsToGo / Kibitz / BoardSlider.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-24  |  17.0 KB  |  626 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:        boardslider.c
  5. ** Written by:  Eric Soldan
  6. **
  7. ** Copyright © 1990-1992 Apple Computer, Inc.
  8. ** All rights reserved. */
  9.  
  10. /* This is a custom slider for Kibitz.  It sends AppleEvents to the opponent,
  11. ** if there is one, so that the remote board is also scrolled.  It sends a
  12. ** maximum of 1 a second, so that they will be able to be processed without
  13. ** stacking up at the other end.
  14. **
  15. ** There is a custom cdef for this code.  All it does is jump to this code.
  16. ** There is a really good reason for this, which is most obscure.  It is
  17. ** possible that, when you choose an opponent machine, you choose your own
  18. ** machine.  This is fully supported in Kibitz.  As a matter of fact, only
  19. ** theMakeTarget code "knows" that it is the same machine.  The rest of the
  20. ** application is completely ignorant of this fact.  When the user clicks
  21. ** on the slider, the control manager locks down the cdef, and then calls it.
  22. ** When the custom cdef returns to the control manager, the cdef is unlocked.
  23. ** This all seems very reasonable.  However, in the case that you are sending
  24. ** a game to the same machine, I send an AppleEvent, which causes an update
  25. ** on the slider.  This update is handled by the control manager calling the
  26. ** cdef.  Of course, it locks it down, and then when the control manager is
  27. ** returned to, it unlocks it.  BUT WAIT!!  We are still tracking the slider
  28. ** that caused the AppleEvent to be sent, which in turn caused the slider of
  29. ** another window to update.  This is true.  It is also true that the cdef
  30. ** is now UNLOCKED!  And with AppleEvents using memory in a healthy way, it
  31. ** is very probable that the cdef will  move.  It isn't a good idea to rts
  32. ** to code that has moved.  This is why the cdef jumps to the code in the
  33. ** application.  We never return to the (potentially unlocked) cdef.  We
  34. ** return straight to the control manager.  Ugly problem, huh? */
  35.  
  36.  
  37.  
  38. /*****************************************************************************/
  39.  
  40.  
  41.  
  42. #define kCapHeight        11
  43. #define kThumbHeight    7
  44. #define kThumbOffset    12
  45. #define kSliderWidth    13
  46.  
  47. #include "Kibitz.h"                /* Get the Kibitz includes/typedefs, etc.    */
  48. #include "KibitzCommon.h"        /* Get the stuff in common with rez.        */
  49. #include "Kibitz.protos"        /* Get the prototypes for Kibitz.            */
  50.  
  51. #ifndef __GWLAYERS__
  52. #include <GWLayers.h>
  53. #endif
  54.  
  55. #ifndef __RESOURCES__
  56. #include <Resources.h>
  57. #endif
  58.  
  59. #ifndef __TOOLUTILS__
  60. #include <ToolUtils.h>
  61. #endif
  62.  
  63. #ifndef __UTILITIES__
  64. #include <Utilities.h>
  65. #endif
  66.  
  67.  
  68.  
  69. /*****************************************************************************/
  70.  
  71.  
  72.  
  73. #if defined(powerc) || defined (__powerc)
  74. #pragma options align=mac68k
  75. #endif
  76. typedef struct cdefRsrcJMP {
  77.     long    jsrInst;
  78.     long    moveInst;
  79.     short    jmpInst;
  80.     long    jmpAddress;
  81. } cdefRsrcJMP;
  82. typedef cdefRsrcJMP *cdefRsrcJMPPtr, **cdefRsrcJMPHndl;
  83. #if defined(powerc) || defined(__powerc)
  84. #pragma options align=reset
  85. #endif
  86.  
  87. static void            BoardDrawCIcon(CIconHandle iconHndl, short hloc, short vloc);
  88. static pascal long    BoardSliderCtl(short varCode, ControlHandle ctl, short msg, long parm);
  89. static void            BoardSliderUpdate(ControlHandle ctl, short hiliteCap);
  90. static Rect            CalcSliderRect(ControlHandle ctl);
  91. static void            TrackSlider(ControlHandle ctl, Point origMouseLoc);
  92.  
  93.  
  94.  
  95. /*****************************************************************************/
  96.  
  97.  
  98.  
  99. /* Given a file reference, adjust the slider to reflect the position
  100. ** of the chessboard. */
  101.  
  102. #pragma segment Controls
  103. void    AdjustGameSlider(FileRecHndl frHndl)
  104. {
  105.     ControlHandle    ctl;
  106.     short            val, max;
  107.     WindowPtr        oldPort;
  108.  
  109.     ctl = (*frHndl)->doc.gameSlider;
  110.     val = (*frHndl)->doc.gameIndex;
  111.     max = (*frHndl)->doc.numGameMoves;
  112.         /* Get the info we need. */
  113.  
  114.     (*ctl)->contrlMax   = max;
  115.     (*ctl)->contrlValue = val;
  116.     oldPort = SetFilePort(frHndl);
  117.     BoardSliderUpdate(ctl, -1);
  118.         /* Change the slider value and show the result. */
  119.  
  120.     SetPort(oldPort);
  121. }
  122.  
  123.  
  124.  
  125. /*****************************************************************************/
  126.  
  127.  
  128.  
  129. #pragma segment Controls
  130. ControlHandle    BoardSliderNew(WindowPtr window)
  131. {
  132.     WindowPtr        oldPort;
  133.     FileRecHndl        frHndl;
  134.     Rect            boardRect;
  135.     ControlHandle    sliderCtl;
  136.     cdefRsrcJMPHndl    cdefRsrc;
  137.     static    ControlDefUPP    boardSliderCtlUPP = nil;
  138.  
  139.     GetPort(&oldPort);
  140.     SetPort(window);
  141.  
  142.     frHndl = (FileRecHndl)GetWRefCon(window);
  143.  
  144.     boardRect = BoardRect();
  145.     boardRect.left    = boardRect.right + 4;
  146.     boardRect.right   = boardRect.left + 13;
  147.     boardRect.top    += 4;
  148.     boardRect.bottom -= 4;
  149.  
  150.     cdefRsrc = (cdefRsrcJMPHndl)GetResource('CDEF', (rSliderCtl / 16));
  151.     if (!boardSliderCtlUPP)
  152.         boardSliderCtlUPP = NewControlDefProc(BoardSliderCtl);
  153.     (*cdefRsrc)->jmpAddress = (long)boardSliderCtlUPP;
  154.     FlushInstructionCache();
  155.         /* Make sure that instruction caches don't kill us. */
  156.  
  157.     sliderCtl = NewControl(window, &boardRect, "\p", true, 0, 0, 0,
  158.                            rSliderCtl, (long)frHndl);
  159.  
  160.     return(sliderCtl);
  161. }
  162.  
  163.  
  164.  
  165. /*****************************************************************************/
  166.  
  167.  
  168.  
  169. #pragma segment Controls
  170. pascal long    BoardSliderCtl(short varCode, ControlHandle ctl, short msg, long parm)
  171. {
  172. #ifndef __MWERKS__
  173. #pragma unused (varCode)
  174. #endif
  175.  
  176.     Rect            viewRect;
  177.     static Point    lastClick;
  178.  
  179.     viewRect = (*ctl)->contrlRect;
  180.  
  181.     switch (msg) {
  182.         case drawCntl:
  183.             BoardSliderUpdate(ctl, -1);
  184.             break;
  185.  
  186.         case testCntl:
  187.             if ((*ctl)->contrlHilite == 255) return(0);
  188.             if (!(*ctl)->contrlMax) return(0);
  189.             if (PtInRect(*(Point *)&parm, &viewRect)) {
  190.                 lastClick = *((Point *)&parm);
  191.                 return(inThumb);
  192.             }        /* Everything is the thumb.  The "thumb" routine will figure
  193.                     ** out what part it is.  Since this is a very specific control,
  194.                     ** we can get away with this simplification. */
  195.             return(0);
  196.  
  197.         case calcCRgns:
  198.         case calcCntlRgn:
  199.             if (msg == calcCRgns) parm &= 0x00FFFFFF;
  200.             RectRgn((RgnHandle)parm, &viewRect);
  201.             break;
  202.  
  203.         case initCntl:
  204.             break;
  205.  
  206.         case dispCntl:
  207.             break;
  208.  
  209.         case posCntl:
  210.             break;
  211.  
  212.         case thumbCntl:
  213.             TrackSlider(ctl, lastClick);
  214.             break;
  215.  
  216.         case dragCntl:
  217.             return(true);
  218.  
  219.         case autoTrack:
  220.             break;
  221.     }
  222.  
  223.     return(0);
  224. }
  225.  
  226.  
  227.  
  228. /*****************************************************************************/
  229.  
  230.  
  231.  
  232. #pragma segment Controls
  233. void    BoardSliderUpdate(ControlHandle ctl, short hiliteCap)
  234. {
  235.     Rect        ctlRect, workRect, sliderRect;
  236.     FileRecHndl    frHndl;
  237.     Boolean        active;
  238.     short        i, j, thumbColor;
  239.     RgnHandle    origClipRgn, clipRgn, workRgn;
  240.     CIconHandle    icons[7];
  241.  
  242.     /* We use color icons here for the various slider parts.  This is so that we
  243.     ** can take advantage of the depth of monitors.  I use icons here so that I
  244.     ** can do a single plot of an icon if the delta of the thumb is -12 to 12.
  245.     ** (The thumb is in the center of an icon, and 12 pixels above and below the
  246.     ** icon, I have slider bar.  Use RedEdit to check it out.)  This technique
  247.     ** gives a very smooth appearance when the thumb slides.  There is no flash.
  248.     ** For deltas greater than +-12, I redraw the slider without the thumb, and
  249.     ** then draw the thumb in the new position.  Since the thumb is moving a lot
  250.     ** anyway, this doesn't show up as a flicker.  There is no overlap in the
  251.     ** old and new positions for a big delta. */
  252.  
  253.     ctlRect = (*ctl)->contrlRect;
  254.     frHndl  = (FileRecHndl)GetControlReference(ctl);
  255.  
  256.     for (i = 0; i < 7; i++) icons[i] = ReadCIcon(i + rSliderBase);
  257.  
  258.     origClipRgn = NewRgn();
  259.     GetClip(origClipRgn);
  260.  
  261.     clipRgn = NewRgn();
  262.  
  263.     for (i = 0; i < 2; i++) {        /* Draw the arrow parts first. */
  264.         j = i;
  265.         if (hiliteCap == i) j += 5;
  266.         workRect = ctlRect;
  267.         if (!i)
  268.             workRect.bottom = workRect.top + kCapHeight;
  269.         else
  270.             workRect.top = workRect.bottom - kCapHeight;
  271.         RectRgn(clipRgn, &workRect);
  272.         SetClip(clipRgn);
  273.             /* Clip out the area outside the arrow part. */
  274.         BoardDrawCIcon(icons[j], workRect.left, workRect.top);
  275.             /* Draw the arrow part. */
  276.     }
  277.  
  278.     ctlRect.top    += kCapHeight;
  279.     ctlRect.bottom -= kCapHeight;
  280.     RectRgn(clipRgn, &ctlRect);
  281.     SetClip(clipRgn);
  282.         /* Clip out everything except the slider bar area. */
  283.  
  284.     active  = ((*ctl)->contrlOwner == FrontWindow());
  285.     if ((*ctl)->contrlHilite == 255) active = false;
  286.     if (!(*ctl)->contrlMax) active = false;
  287.  
  288.     if (active) {        /* If control active, draw the thumb. */
  289.         sliderRect = CalcSliderRect(ctl);
  290.         thumbColor = (((*ctl)->contrlValue & 0x01) ^ (*frHndl)->doc.startColor);
  291.         BoardDrawCIcon(icons[3 + thumbColor],
  292.                        sliderRect.left, sliderRect.top - kThumbOffset);
  293.         workRgn = NewRgn();
  294.         RectRgn(workRgn, &sliderRect);
  295.         DiffRgn(clipRgn, workRgn, clipRgn);
  296.         SetClip(clipRgn);
  297.         DisposeRgn(workRgn);
  298.             /* Now that the thumb is drawn, protect it by clipping it out. */
  299.     }
  300.  
  301.     for (i = ctlRect.top; i < ctlRect.bottom; i += 32)
  302.         BoardDrawCIcon(icons[2], ctlRect.left, i);
  303.             /* Draw the slider bar portion. */
  304.  
  305.     /* It is now completely drawn.  Clean up and get out. */
  306.  
  307.     SetClip(origClipRgn);
  308.     DisposeRgn(clipRgn);
  309.     DisposeRgn(origClipRgn);
  310.  
  311.     for (i = 0; i < 7; i++) KillCIcon(icons[i]);
  312. }
  313.  
  314.  
  315.  
  316. /*****************************************************************************/
  317.  
  318.  
  319.  
  320. #pragma segment Controls
  321. void    BoardDrawCIcon(CIconHandle iconHndl, short hloc, short vloc)
  322. {
  323.     Rect    iconRect;
  324.  
  325.     iconRect.right  = (iconRect.left = hloc) + 32;
  326.     iconRect.bottom = (iconRect.top  = vloc) + 32;
  327.  
  328.     DrawCIcon(iconHndl, iconRect);
  329. }
  330.  
  331.  
  332.  
  333. /*****************************************************************************/
  334.  
  335.  
  336.  
  337. #pragma segment Controls
  338. Rect    CalcSliderRect(ControlHandle ctl)
  339. {
  340.     Rect    ctlRect, sliderRect;
  341.     short    max, val;
  342.     long    calc;
  343.  
  344.     ctlRect = (*ctl)->contrlRect;
  345.     ctlRect.top    += kCapHeight;
  346.     ctlRect.bottom -= kCapHeight;
  347.     max = (*ctl)->contrlMax;
  348.     val = (*ctl)->contrlValue;
  349.  
  350.     calc = ctlRect.bottom - ctlRect.top - kThumbHeight;
  351.     calc *= val;
  352.     if (max) calc /= max;
  353.     sliderRect.top    = ctlRect.top + calc,
  354.     sliderRect.left   = ctlRect.left;
  355.     sliderRect.bottom = sliderRect.top + kThumbHeight;
  356.     sliderRect.right  = ctlRect.right;
  357.  
  358.     return(sliderRect);
  359. }
  360.  
  361.  
  362.  
  363. /*****************************************************************************/
  364.  
  365.  
  366.  
  367. #pragma segment Controls
  368. void    TrackSlider(ControlHandle ctl, Point origMouseLoc)
  369. {
  370.     CIconHandle    icons[7];
  371.     WindowPtr    oldPort;
  372.     Rect        ctlRect, sliderRange, slopRect, sliderRect, capRect, pgRect;
  373.     FileRecHndl    frHndl;
  374.     RgnHandle    origClipRgn, clipRgn, workRgn;
  375.     short        i, max, val, origGameIndex, ovloc, voffset, vloc, delta, hiliteCap;
  376.     Boolean        twoPlayer, hiliteOn, doPgScroll;
  377.     long        origTick, tick, calc;
  378.     Point        lastMouseLoc, mouseLoc;
  379.  
  380.     /* Get everything we need set up. */
  381.  
  382.     origTick = tick = TickCount();
  383.  
  384.     for (i = 2; i < 5; i++) icons[i] = ReadCIcon(i + rSliderBase);
  385.  
  386.     frHndl  = (FileRecHndl)GetControlReference(ctl);
  387.     oldPort = SetFilePort(frHndl);
  388.     ctlRect = (*ctl)->contrlRect;
  389.  
  390.     origClipRgn = NewRgn();
  391.     GetClip(origClipRgn);
  392.  
  393.     clipRgn = NewRgn();
  394.     workRgn = NewRgn();
  395.  
  396.     origGameIndex = (*frHndl)->doc.gameIndex;
  397.     max = (*ctl)->contrlMax;
  398.  
  399.     twoPlayer  = (*frHndl)->doc.twoPlayer;
  400.     sliderRect = CalcSliderRect(ctl);
  401.  
  402.     /* That ought to be enough setup. */
  403.  
  404.     if (PtInRect(origMouseLoc, &sliderRect)) {    /* If they are on the thumb... */
  405.  
  406.         ctlRect.top    += kCapHeight;            /* Protect the arrow parts. */
  407.         ctlRect.bottom -= kCapHeight;
  408.         RectRgn(clipRgn, &ctlRect);
  409.         SetClip(clipRgn);
  410.  
  411.         sliderRange = ctlRect;                    /* Calc area thumb can move. */
  412.         sliderRange.bottom -= kThumbHeight;        /* Count height of thumb against range. */
  413.  
  414.         slopRect = sliderRange;                    /* Give the user some slop. */
  415.         InsetRect(&slopRect, -20, -20);
  416.  
  417.         lastMouseLoc = origMouseLoc;
  418.         voffset = lastMouseLoc.v - sliderRect.top;
  419.         ovloc   = lastMouseLoc.v - voffset;
  420.  
  421.         while (StillDown()) {
  422.  
  423.             if (tick + 30 < TickCount()) {        /* Send max 1 AppleEvent per 1/2 sec. */
  424.                 tick = TickCount();
  425.                 if (twoPlayer) SendGame(frHndl, kScrolling, nil);
  426.             }
  427.  
  428.             GetMouse(&mouseLoc);
  429.             if (!EqualPt(mouseLoc, lastMouseLoc)) {        /* The mouse has moved. */
  430.  
  431.                 if (!PtInRect(mouseLoc, &slopRect)) mouseLoc = origMouseLoc;
  432.                     /* Outside slopRect, so snap back to the original position. */
  433.  
  434.                 vloc = mouseLoc.v - voffset;
  435.                 if (vloc < sliderRange.top)    vloc = sliderRange.top;
  436.                 if (vloc > sliderRange.bottom) vloc = sliderRange.bottom;
  437.                 delta = vloc - ovloc;
  438.                     /* The delta tells us how much the thumb moved. */
  439.  
  440.                 if (
  441.                     (delta < -((32 - kThumbHeight) / 2)) ||
  442.                     (delta >  ((32 - kThumbHeight) / 2))
  443.                 ) {
  444.                     for (i = ctlRect.top; i < ctlRect.bottom; i += 32)
  445.                         BoardDrawCIcon(icons[2], ctlRect.left, i);
  446.                             /* The thumb moved too far for a single plot to cover
  447.                             ** up the old position, so clear the old thumb. */
  448.                 }
  449.  
  450.                 calc  = max + 1;        /* Force below math to be with longs. */
  451.                 calc *= (vloc - sliderRange.top);
  452.                     /* We use max + 1 because there is one more game
  453.                     ** move position than moves in the game.  This is
  454.                     ** because we can position in front of the first move,
  455.                     ** as well as after the last move. */
  456.                 calc /= (sliderRange.bottom - sliderRange.top);
  457.  
  458.                 val = calc;
  459.                 if (val > max) val = max;
  460.                 if (val < 0)   val = 0;
  461.                 if (delta)
  462.                     BoardDrawCIcon(icons[3 + ((val + (*frHndl)->doc.startColor) & 0x01)],
  463.                                    ctlRect.left, vloc - kThumbOffset);
  464.                                         /* The thumb is now updated. */
  465.  
  466.                 SetClip(origClipRgn);
  467.                 RepositionBoard(frHndl, val, true);
  468.                     /* We set the clipRgn back to the original so the board
  469.                     ** can update.  (Pretty boring if it doesn't. */
  470.  
  471.                 SetClip(clipRgn);
  472.                     /* Back to our normally scheduled program... */
  473.  
  474.                 lastMouseLoc = mouseLoc;
  475.                 (*ctl)->contrlValue = val;
  476.                 ovloc = vloc;
  477.             }
  478.         }
  479.     }
  480.  
  481.     else {        /* We missed the thumb.  See if we hit an arrow part... */
  482.         delta = hiliteOn = 0;
  483.         capRect = ctlRect;
  484.         capRect.bottom = ctlRect.top + kCapHeight;
  485.         if (PtInRect(origMouseLoc, &capRect)) {
  486.             delta = -1;
  487.             hiliteCap = 0;
  488.         }
  489.         else {
  490.             capRect = ctlRect;
  491.             capRect.top = ctlRect.bottom - kCapHeight;
  492.             if (PtInRect(origMouseLoc, &capRect)) {
  493.                 delta = 1;
  494.                 hiliteCap = 1;
  495.             }
  496.         }
  497.  
  498.         if (delta) {    /* We hit an arrow, and there is a change to do... */
  499.             do {
  500.                 if (tick + 30 < TickCount()) {
  501.                     tick = TickCount();
  502.                     if (twoPlayer) SendGame(frHndl, kScrolling, nil);
  503.                 }
  504.                 GetMouse(&mouseLoc);
  505.                 if (PtInRect(mouseLoc, &capRect)) {        /* Still in arrow... */
  506.                     val = (*ctl)->contrlValue + delta;
  507.                     if ((val >= 0) && (val <= max)) {    /* Still scrolling... */
  508.                         hiliteOn = true;
  509.                         (*ctl)->contrlValue = val;
  510.                         BoardSliderUpdate(ctl, hiliteCap);
  511.                         SetClip(origClipRgn);
  512.                         if (RepositionBoard(frHndl, val, true)) SetClip(clipRgn);
  513.                     }
  514.                     else {        /* Scrolled as far as we can go, so unhilite arrow. */
  515.                         if (hiliteOn) {
  516.                             BoardSliderUpdate(ctl, -1);
  517.                             hiliteOn = false;
  518.                         }
  519.                     }
  520.                 }
  521.                 else {        /* Outside arrow, so unhilite it. */
  522.                     if (hiliteOn) {
  523.                         BoardSliderUpdate(ctl, -1);
  524.                         hiliteOn = false;
  525.                     }
  526.                 }
  527.  
  528.                 while ((StillDown()) && (origTick + 20 > TickCount())) {};
  529.                     /* Don't go too fast. */
  530.  
  531.             } while (StillDown());
  532.         }
  533.  
  534.         else {
  535.  
  536.             pgRect = ctlRect;
  537.             pgRect.top    += kCapHeight;
  538.             pgRect.bottom -= kCapHeight;
  539.             if (PtInRect(origMouseLoc, &pgRect)) {        /* If in the page area... */
  540.                 delta = (origMouseLoc.v < sliderRect.top) ? -2 : 2;
  541.                 InsetRect(&pgRect, -10, -10);
  542.                 do {
  543.                     if (tick + 30 < TickCount()) {
  544.                         tick = TickCount();
  545.                         if (twoPlayer) SendGame(frHndl, kScrolling, nil);
  546.                     }
  547.                     GetMouse(&mouseLoc);
  548.                     if (PtInRect(mouseLoc, &pgRect)) {        /* Still in page area... */
  549.                         doPgScroll = false;
  550.                         sliderRect = CalcSliderRect(ctl);
  551.                         if ((delta == -2) && (mouseLoc.v < sliderRect.top))    doPgScroll = true;
  552.                         if ((delta == 2)  && (mouseLoc.v > sliderRect.bottom)) doPgScroll = true;
  553.                         if (doPgScroll) {
  554.                             val = (*ctl)->contrlValue + delta;
  555.                             if (val == -1)       val = 0;
  556.                             if (val == (max + 1)) val = max;
  557.                             if ((val >= 0) && (val <= max)) {    /* Still scrolling... */
  558.                                 (*ctl)->contrlValue = val;
  559.                                 BoardSliderUpdate(ctl, -1);
  560.                                 SetClip(origClipRgn);
  561.                                 if (RepositionBoard(frHndl, val, true)) SetClip(clipRgn);
  562.                             }
  563.                         }
  564.                     }
  565.  
  566.                     while ((StillDown()) && (origTick + 20 > TickCount())) {};
  567.                         /* Don't go too fast. */
  568.  
  569.                 } while (StillDown());
  570.             }
  571.         }
  572.     }
  573.  
  574.     SetClip(origClipRgn);
  575.     DisposeRgn(workRgn);
  576.     DisposeRgn(clipRgn);
  577.     DisposeRgn(origClipRgn);
  578.  
  579.     if (twoPlayer) SendGame(frHndl, kResync, nil);
  580.         /* Make sure that the result from the scroll isn't ignored.  The
  581.         ** opponent may ignore the events while we are scrolling, but not
  582.         ** when we are done. */
  583.  
  584.     BoardSliderUpdate(ctl, -1);
  585.         /* Snap the slider to a move position.  The user may have let go of the
  586.         ** slider at a position that doesn't map exactly to the game position. */
  587.  
  588.     for (i = 2; i < 5; i++) KillCIcon(icons[i]);
  589.  
  590.     SetPort(oldPort);
  591. }
  592.  
  593.  
  594.  
  595. /*****************************************************************************/
  596.  
  597.  
  598.  
  599. #pragma segment Controls
  600. Boolean    RepositionBoard(FileRecHndl frHndl, short newPos, Boolean update)
  601. {
  602.     short        oldPos, delta;
  603.  
  604.     oldPos = (*frHndl)->doc.gameIndex;
  605.     if (newPos == oldPos) return(false);
  606.  
  607.     delta  = (newPos > oldPos) ? 1 : -1;
  608.         /* We need to walk the board forward or backward delta number of moves. */
  609.  
  610.     for (; oldPos != newPos; oldPos += delta)
  611.         MakeMove(frHndl, delta, 0, 0);
  612.             /* Walk the board position one half-move forward or backward. */
  613.  
  614.     if (update) {
  615.         ImageDocument(frHndl, true);
  616.         DrawButtonTitle(frHndl, (*frHndl)->doc.twoPlayer);
  617.         UpdateGameStatus(frHndl);
  618.             /* Show the new board position. */
  619.     }
  620.  
  621.     return(true);
  622. }
  623.  
  624.  
  625.  
  626.